package com.wei.czz.framework.admin.controller;

import com.wei.czz.common.annotation.Auth;
import com.wei.czz.common.annotation.Resubmit;
import com.wei.czz.common.dto.admin.menu.MenuDto;
import com.wei.czz.common.dto.admin.roleMenu.MenuRoleDto;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.property.BatchProperty;
import com.wei.czz.common.tool.Result;
import com.wei.czz.common.vo.admin.roleMenu.MenuRoleVo;
import com.wei.czz.common.vo.admin.roleMenu.RoleMenuVo;
import com.wei.czz.framework.admin.manager.MenuManager;
import com.wei.czz.framework.admin.manager.RoleManager;
import com.wei.czz.framework.admin.manager.RoleMenuManager;
import com.wei.czz.framework.admin.service.RoleMenuService;
import com.wei.czz.framework.common.service.AsyncService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;


/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2022-08-28 13:36:58
 * className: RoleMenuController 角色与菜单操作请求接口类
 * version: 1.0
 * description:
 */
@RestController
@RequestMapping("sys/role-menu")
@AllArgsConstructor
public class RoleMenuController {

    private static final Logger log = LoggerFactory.getLogger(RoleMenuController.class);

    private final BatchProperty batchProperty;

    private final RoleMenuManager roleMenuManager;

    private final RoleMenuService roleMenuService;

    private final RoleManager roleManager;

    private final MenuManager menuManager;

    private final AsyncService asyncService;

    /**
     * 获取菜单树数据接口
     * 根据角色主键，获取菜单相关数据
     * 1、获取菜单树数据
     * 2、获取角色关联菜单数据
     * <p>
     * 调用方：
     *  1、浏览器-后台-角色管理页-角色授权弹出框中调用
     *
     * @param roleId 角色主键
     * @return 菜单相关数据
     */
    @GetMapping("/data")
    @Auth(permit = "system:role:auth")
    public Result<Map<String, Object>> getRoleMenuData(@RequestParam("roleId") Long roleId) {
        log.info("开始获取菜单树数据业务。 roleId={}", roleId);

        // 异步获取菜单树数据
        CompletableFuture<TreeSet<MenuDto>> future = asyncService.supplyAsync(menuManager::finMenuTree);

        List<String> menuIdList = roleMenuService.getRoleMenuIdList(roleId);

        TreeSet<MenuDto> menuDtoSet;
        try {
            menuDtoSet = future.get();
        } catch (InterruptedException | ExecutionException e) {
            log.error("异步查询菜单树数据失败。message={}", e.getMessage(), e);
            return Result.getResult(ResultEnum.SERVICE_FAIL);
        }
        Map<String, Object> map = new HashMap<>(8);
        map.put("menuTree", menuDtoSet);
        map.put("menuIdList", menuIdList);

        log.info("获取菜单树数据业务结束");
        return Result.success(map);
    }

    /**
     * 获取菜单关联角色相关数据接口
     * 根据菜单主键
     * 1、获取菜单已关联角色列表
     * 2、获取菜单已关联部门下的角色列表（部门已关联的角色列表）
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-菜单管理也页-菜单关联角色弹出框中调用
     * @param menuId 菜单主键
     * @return 菜单关联角色相关数据
     */
    @GetMapping("/relation/data")
    @Auth(permit = "system:menu:update")
    public Result<MenuRoleDto> getMenuRoleRelationData(@RequestParam("menuId") Long menuId) {
        log.info("开始获取菜单关联角色相关数据业务。menuId={}", menuId);

        MenuRoleDto menuRoleDto = roleManager.getMenuRoleRelationData(menuId);

//        List<MenuRoleDto> menuRoleDtoList = roleMenuService.getMenuRoleList(menuId);

        log.info("获取菜单关联角色相关数据业务结束");
        return Result.success(menuRoleDto);
    }

    /**
     * 修改角色关联菜单数据接口
     * 根据角色主键和菜单主键列表，变更角色关联菜单数据
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-角色管理页-角色授权弹出框中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param roleMenuVo 角色参数对象
     * @return 不返回数据
     */
    @Resubmit(spEL = "'updateRoleMenu' + #userPo.userId", message = "角色关联菜单")
    @PostMapping("/update")
    @Auth(permit = "system:role:update")
    public Result<Object> updateRoleMenu(@Validated @RequestBody RoleMenuVo roleMenuVo) {
        log.info("开始修改角色关联菜单数据业务。{}", roleMenuVo);

        List<Long> menuIdList = roleMenuVo.getMenuIdList();
        if (batchProperty.getMaxSize() < menuIdList.size()) {
            log.warn("菜单主键列表超限。batch.maxSize={} list.size={}", batchProperty.getMaxSize(), menuIdList.size());
            return Result.clientFail("一次角色关联菜单操作最多允许同时关联" + batchProperty.getMaxSize() + "个菜单");
        }

        roleMenuManager.updateRoleMenu(roleMenuVo.getRoleId(), menuIdList);

        log.info("修改角色关联菜单数据业务结束");
        return Result.success();
    }

    /**
     * 修改菜单关联角色数据接口
     * 根据菜单主键和角色主键列表，变更菜单关联角色数据
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页-菜单管理页-菜单关联角色弹出框中调用
     * <p>
     * 此接口会校验是否重复提交
     * @param menuRoleVo 参数对象
     */
    @Resubmit(spEL = "'modifyMenuRole' + #userPo.userId", message = "角色关联菜单")
    @PostMapping("/modify")
    @Auth(permit = "system:menu:update')")
    public Result<Object> modifyMenuRole(@Validated @RequestBody MenuRoleVo menuRoleVo) {
        log.info("开始修改菜单关联角色数据业务。{}", menuRoleVo);

        List<Long> roleIdList = menuRoleVo.getRoleIdList();
        if (batchProperty.getMaxSize() < roleIdList.size()) {
            log.warn("角色主键列表超限。batch.maxSize={} list.size={}", batchProperty.getMaxSize(), roleIdList.size());
            return Result.clientFail("一次菜单关联角色操作最多允许同时关联" + batchProperty.getMaxSize() + "个角色");
        }

        roleMenuManager.updateMenuRole(menuRoleVo.getMenuId(), roleIdList);

        log.info("修改菜单关联角色数据业务结束");
        return Result.success();
    }
}
